package com.java.mall_imooc.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.java.mall_imooc.common.enums.ProductStatusEnum;
import com.java.mall_imooc.common.enums.ResultEnum;
import com.java.mall_imooc.common.utils.Constant;
import com.java.mall_imooc.common.utils.R;
import com.java.mall_imooc.entity.Cart;
import com.java.mall_imooc.entity.Product;
import com.java.mall_imooc.form.CartAddForm;
import com.java.mall_imooc.form.CartUpdateForm;
import com.java.mall_imooc.service.CartService;
import com.java.mall_imooc.service.ProductService;
import com.java.mall_imooc.vo.CartProductVo;
import com.java.mall_imooc.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author jiangli
 * @since 2020-03-16 21:17
 */
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private ProductService productService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    private HashOperations<String, String, String> opsForHash;

    @PostConstruct
    public void init() {
        opsForHash = redisTemplate.opsForHash();
    }

    @Override
    public R<CartVo> list(Integer userId) {
        CartVo cartVo = new CartVo();
        List<CartProductVo> cartProductVos = new ArrayList<>();
        // 缓存 用hash结构
//        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = Constant.CART_REDIS_KEY + userId;
        Map<String, String> entries = opsForHash.entries(key);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Integer productId = Integer.valueOf(entry.getKey());
            Cart cart = JSONUtil.toBean(entry.getValue(), Cart.class);
            Product product = productService.getById(productId);

            if (product != null) {
                CartProductVo cartProductVo = CartProductVo.builder().productId(productId).productName(product.getName()).productPice(product.getPrice()).productStatus(product.getStatus())
                        .productSubtitle(product.getSubtitle()).productMainImage(product.getMainImage()).productStock(product.getStock()).quantity(cart.getQuantity()).productSelected(cart.getProductSelected()).productTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity()))).build();
                cartProductVos.add(cartProductVo);
            }
        }
        cartVo.setCartProductVoList(cartProductVos);
        // 是否全选
        cartVo.setSelectAll(cartProductVos.stream().allMatch(CartProductVo::getProductSelected));
        // 总数量
        int sum = cartProductVos.stream().mapToInt(CartProductVo::getQuantity).sum();
        cartVo.setCartTotalQuantity(sum);
        // 总价格(只计算选中的)
        BigDecimal price = cartProductVos.stream().filter(CartProductVo::getProductSelected).map(CartProductVo::getProductTotalPrice).reduce(new BigDecimal("0"), BigDecimal::add);
        cartVo.setCartTotalPrice(price);
        return R.ok(cartVo);
    }

    @Override
    public R<CartVo> add(@Valid CartAddForm cartAddForm, Integer userId) {
        Integer quantity = 1;
        Product product = productService.getById(cartAddForm.getProductId());
        if (product == null) {
            return R.error(ResultEnum.PRODUCT_NOT_EXIST);
        }
        if (product.getStatus().equals(ProductStatusEnum.OFF_SALE) || product.getStatus().equals(ProductStatusEnum.DELETED)) {
            return R.error(ResultEnum.PRODUCT_OFF_SALE_OR_DELETED);
        }
        // 库存
        if (product.getStock() <= 0) {
            return R.error(ResultEnum.PRODUCT_STOCK_NOT_ENOUGH);
        }
        // 缓存 用hash结构
        String key = Constant.CART_REDIS_KEY + userId;
        String value = opsForHash.get(key, String.valueOf(cartAddForm.getProductId()));
        // 商品数量累加
        Cart cart;
        if (StrUtil.isEmpty(value)) {
            cart = new Cart(cartAddForm.getProductId(), quantity, cartAddForm.getSelected());
        } else {
            // 数量累加
            cart = JSONUtil.toBean(value, Cart.class);
            cart.setQuantity(cart.getQuantity() + quantity);
        }

        opsForHash.put(key, String.valueOf(cartAddForm.getProductId()), JSONUtil.toJsonStr(cart));
        return list(userId);
    }

    @Override
    public R<CartVo> update(Integer userId, Integer productId, CartUpdateForm cartUpdateForm) {
        // 缓存 用hash结构
        String key = Constant.CART_REDIS_KEY + userId;
        String value = opsForHash.get(key, String.valueOf(productId));

        if (StrUtil.isEmpty(value)) {
            return R.error(ResultEnum.CART_PRODUCT_NOT_EXIST);
        }
        // 修改数据
        Cart cart = JSONUtil.toBean(value, Cart.class);
        if (cartUpdateForm.getQuantity() != null && cartUpdateForm.getQuantity() > 0) {
            cart.setQuantity(cartUpdateForm.getQuantity());
        }
        if (cartUpdateForm.getSelected() != null) {
            cart.setProductSelected(cartUpdateForm.getSelected());
        }

        opsForHash.put(key, String.valueOf(productId), JSONUtil.toJsonStr(cart));
        return list(userId);
    }

    @Override
    public R<CartVo> delete(Integer userId, Integer productId) {
        // 缓存 用hash结构
        String key = Constant.CART_REDIS_KEY + userId;
        String value = opsForHash.get(key, String.valueOf(productId));

        if (StrUtil.isEmpty(value)) {
            return R.error(ResultEnum.CART_PRODUCT_NOT_EXIST);
        }

        opsForHash.delete(key, String.valueOf(productId));

        // 如果购物车没有数据则redis会自动删除key
        return list(userId);
    }

    @Override
    public R<CartVo> selectAll(Integer userId) {
        String key = Constant.CART_REDIS_KEY + userId;
        List<Cart> carts = this.carts(key);
        carts.forEach(e-> {
            e.setProductSelected(true);
            opsForHash.put(key, String.valueOf(e.getProductId()), JSONUtil.toJsonStr(e));
        });
        return list(userId);
    }

    @Override
    public R<CartVo> unSelectAll(Integer userId) {
        String key = Constant.CART_REDIS_KEY + userId;
        List<Cart> carts = this.carts(key);
        carts.forEach(e-> {
            e.setProductSelected(false);
            opsForHash.put(key, String.valueOf(e.getProductId()), JSONUtil.toJsonStr(e));
        });
        return list(userId);
    }

    @Override
    public R<Integer> sum(Integer userId) {
        String key = Constant.CART_REDIS_KEY + userId;
        List<Cart> carts = this.carts(key);
        Integer sum = carts.stream().mapToInt(Cart::getQuantity).sum();
        return R.ok(sum);
    }

    public List<Cart> carts(String key) {
        List<Cart> carts = new ArrayList<>();
        // 缓存 用hash结构
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        Map<String, String> entries = opsForHash.entries(key);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = JSONUtil.toBean(entry.getValue(), Cart.class);
            carts.add(cart);
        }
        return carts;
    }
}
